#include <iostream>
#include <SFML/Window.hpp>
// #include <SFML/OpenGL.hpp>
// #include <glm.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "tools.hpp"
#include "glad/glad.h"
#include <glm/gtc/matrix_transform.hpp>
#include "vertex.hpp"
#include <chrono>
#include <stack>
#include "sphere.h"
using namespace sf;
using namespace glm;
using namespace std::chrono;
using std::cout, std::endl;
constexpr uint8 vboNums = 5;
GLuint vao[1];
GLuint vbo[vboNums];
GLuint program;

constexpr int width = 1000;
constexpr int height = 1000;

mat4 pMat, vMat, mMat, mvMat;
float aspect;
float cameraX, cameraY, cameraZ;
float cubeLocX, cubeLocY, cubeLocZ;
Sphere mySphere;
std::stack<mat4> mvstack;
std::vector<int> ind;
std::vector<glm::vec3> vert;
std::vector<glm::vec2> tex;
std::vector<glm::vec3> norm;
void init();
void display(const Window& window);
int main()
{
    sf::Window window(sf::VideoMode({width, height}), "OpenGL");
    window.setFramerateLimit(60);
    gladLoadGL();
    bool isRunning = true;
    // activate the window
    window.setActive(true);
    // 设置 OpenGL 的初始状态
    glClearDepth(1.f);
    glClearColor(0.2f, 0.3f, 0.3f, 1.f); // 背景色
    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);
    init();
    while (isRunning) {
        while (auto e = window.pollEvent()) {
            if (e->is<Event::Closed>()) {
                isRunning = false;
            }
        }

        // 绘制一个简单的三角形
        display(window);
        // end the current frame (internally swaps the front and back buffers)
        window.display();
    }
    return 0;
}
void init()
{

    program = createProgram("../shaders/vertex.vert", "../shaders/fragment.frag");

    ind = mySphere.getIndices();
    vert = mySphere.getVertices();
    tex = mySphere.getTexCoords();
    norm = mySphere.getNormals();

    std::vector<float> pvalues; // 顶点位置
    std::vector<float> tvalues; // 纹理坐标
    std::vector<float> nvalues; // 法向量
    int numIndices = mySphere.getNumIndices();
    for (int i = 0; i < numIndices; i++) {
        pvalues.push_back((vert[ind[i]]).x);
        pvalues.push_back((vert[ind[i]]).y);
        pvalues.push_back((vert[ind[i]]).z);
        tvalues.push_back((tex[ind[i]]).s);
        tvalues.push_back((tex[ind[i]]).t);
        nvalues.push_back((norm[ind[i]]).x);
        nvalues.push_back((norm[ind[i]]).y);
        nvalues.push_back((norm[ind[i]]).z);
    }

    cameraX = 0.0f, cameraY = 0.0f, cameraZ = 12.0f;
    cubeLocX = 0.0f, cubeLocY = 0.0f, cubeLocZ = 0.0f;

    glGenVertexArrays(1, vao);
    glBindVertexArray(vao[0]);
    glGenBuffers(2, vbo);

    // glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    // glBufferData(GL_ARRAY_BUFFER, sizeof(rectangle), rectangle, GL_STATIC_DRAW);
    //
    // glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    // glBufferData(GL_ARRAY_BUFFER, sizeof(pyramidPositions), pyramidPositions, GL_STATIC_DRAW);

    // 把顶点放入缓冲区 0
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glBufferData(GL_ARRAY_BUFFER, pvalues.size()*4, &pvalues[0], GL_STATIC_DRAW);
    // 把纹理坐标放入缓冲区 1
    glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
    glBufferData(GL_ARRAY_BUFFER, tvalues.size()*4, &tvalues[0], GL_STATIC_DRAW);
    // 把法向量放入缓冲区 2
    glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
    glBufferData(GL_ARRAY_BUFFER, nvalues.size()*4, &nvalues[0], GL_STATIC_DRAW);


}

void display(const Window& window)
{
    // duration_cast<milliseconds>()
    static auto lastTime = high_resolution_clock::now();
    duration<float, std::milli> now =  high_resolution_clock::now() - lastTime;
    auto currentTime = now.count();
    static float deltaTime = 15.0f;

    // clear the buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // 调整 OpenGL 设置，绘制模型
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glUseProgram(program);

    auto mvLoc = glGetUniformLocation(program, "modelView");
    auto projLoc = glGetUniformLocation(program, "perspective");

    // 构建透视矩阵
    auto size = window.getSize();
    aspect = size.x * 1.0f / size.y; // 横纵比
    pMat = perspective(1.0472f, aspect, 0.1f, 1000.0f); // 视野范围在60度
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(pMat));

    // 构建视图矩阵、模型矩阵和 MV 矩阵
    vMat = translate(glm::mat4(1.0f), glm::vec3(-cameraX, -cameraY, -cameraZ));
    mvstack.push(vMat);
    // 对太阳进行变换
    mvstack.push(mvstack.top());
    mvstack.top() *= translate(mat4(1.0f), vec3{0, 0, 0}); // 太阳不动
    mvstack.push(mvstack.top());
    // cout << currentTime << endl;
    mvstack.top() *= rotate(mat4(1.0f), deltaTime, vec3{0.0f, 1.0, 0}); // 太阳自转
    const auto num = mySphere.getNumIndices();
    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, glm::value_ptr(mvstack.top()));
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, num);
    // 移除太阳自转
    mvstack.pop();

    // 绘制地球
    mvstack.push(mvstack.top());
    // 公转 自转 然后移除自转
    mvstack.top() *= translate(mat4(1.0f), vec3(sin(deltaTime)*5.0, 0.0f, cos(deltaTime)*5.0));
    mvstack.push(mvstack.top());
    mvstack.top() *= rotate(mat4(1.0f), deltaTime, vec3(1.0, 1.0, 0.0));
    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, value_ptr(mvstack.top()));
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, num);
    mvstack.pop();
    // 月球 公转 自转 还要让自己小一些
    mvstack.push(mvstack.top());
    mvstack.top() *= translate(mat4(1.0f), vec3(0.0f, cos(deltaTime)*2.5, sin(deltaTime)*2.5));
    mvstack.top() *= rotate(mat4(1.0f), deltaTime * 2, vec3(1.0, 0.0, 1.0));
    mvstack.top() *= scale(mat4(1.0f), vec3(0.5, 0.5, 0.5f));
    glUniformMatrix4fv(mvLoc, 1, GL_FALSE, value_ptr(mvstack.top()));
    glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, num);

    mvstack.pop(); // 月球
    mvstack.pop(); // 地球公转
    mvstack.pop(); // 太阳公转
    mvstack.pop(); // 摄像机

    deltaTime += 0.03;

}